package com.chinamsp.dydb.crud;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import com.chinamsp.dydb.query.Condition;
import com.chinamsp.dydb.query.ConditionMap;
import com.chinamsp.dydb.query.OrderBy;
import com.chinamsp.dydb.query.Pagination;

/**
 * service 层的基类，所有service类必须继承自此类，该类不能直接使用。
 * <p>
 * 将service层一些通用的操作给抽离出来，封装到此类中，其他service类必须继承此类，子类可以直接使用此类中的方法。<br/>
 * 该类使用泛型实现了实体和dao层封装，子类继承此方法时必须指明对应的Model和Dao具体实现类，在{@link #setBaseDao(BaseDao)}方法中使用spring注解方式实现。<br/>
 * 子类在需要使用dao对象的地方，直接调用baseDao.<i>method()</i>，该类当前只支持自动装配一个dao实例，如果需要多个，在自己的service类中以spring注解方式自行配置。
 * </p>
 * 
 * @param <T>
 *            主要操作的实体类型
 * @param <K>
 *            主要操作的Dao类型
 */
public abstract class BaseBiz<T extends BaseModel, K extends BaseDao<T>> {

	// private Class<T> entityClass;

	private final List<Condition> emptyConditions = new ArrayList<Condition>();

	/**
	 * dao原型属性
	 */
	protected K baseDao;

	/**
	 * 根据K泛型自动装载BaseDao
	 * 
	 * @param baseDao
	 */
	@Autowired
	public void setBaseDao(K baseDao) {
		this.baseDao = baseDao;
	}

	/**
	 * 根据 id 删除实例
	 * @param id
	 */
	public void deleteById(Object id) {
		baseDao.deleteById(String.valueOf(id));
	}

	/**
	 * 删除实体
	 * 
	 * @param entity
	 */
	public void delete(T entity) {
		Assert.notNull(entity, "要删除的实例不存在");
		deleteById(entity.getId());
	}

	
	public T findById(Object id) {
		if (StringUtils.isEmpty(id)) {
			return null;
		}
		return baseDao.findById(id.toString());
	}

	/**
	 * 获取批量数据
	 * <p>
	 * 该方法只是简单的循环调用findById方法实现，如果需要提高效率，请自行实现baoseDao find
	 * </p>
	 * 
	 * @param ids
	 * @return
	 *
	 * @author shifenghu
	 * @date 2013-12-19
	 */
	public List<T> findByIds(List<String> ids) {
		List<T> list = new ArrayList<T>(ids.size());
		T obj;
		if (!CollectionUtils.isEmpty(ids)) {
			for (String id : ids) {
				obj = findById(id);
				if (obj != null) {
					list.add(obj);
				}
			}
		}
		return list;
	}

	/**
	 * 根据分页和条件进行查询。如果不需要分页，把pagination设为null。 主要是为了方便一个条件的查询，不用在调用时自己封装成List
	 * 
	 * @param pagination
	 * @param condition
	 * @return
	 */
	public List<T> find(Pagination pagination, Condition condition) {
		List<Condition> conditions = null;

		if (condition != null) {
			conditions = new ArrayList<Condition>();
			conditions.add(condition);
		}
		return find(pagination, conditions);
	}

	/**
	 * 根据分页和条件进行查询。如果不需要分页，把pagination设为null。
	 * 
	 * @param pagination
	 * @param conditions
	 * @return
	 */
	public List<T> find(Pagination pagination, ConditionMap conditions) {
		List<Condition> conditionList = null;
		if (conditions != null) {
			conditionList = conditions.getItems();
		}
		return find(pagination, conditionList);
	}

	/**
	 * 查询
	 * 
	 * @param pagination
	 * @param conditions
	 * @param orderBy
	 * @return
	 */
	public List<T> find(Pagination pagination, ConditionMap conditions, OrderBy orderBy) {
		List<Condition> conditionList = null;
		if (conditions != null) {
			conditionList = conditions.getItems();
		}
		return find(pagination, conditionList, Arrays.asList(orderBy));
	}

	/**
	 * 查找所有的记录
	 * 
	 * @return
	 */
	public List<T> findAll() {
		return find(null, emptyConditions);
	}

	/**
	 * 根据分页和条件进行查询。如果不需要分页，把pagination设为null。
	 * 
	 * @param pagination
	 * @param conditions
	 * @return
	 */
	public List<T> find(Pagination pagination, List<Condition> conditions) {
		return baseDao.find(pagination, conditions, null);
	}
	
	/**
	 * 根据分页和条件进行查询。如果不需要分页，把pagination设为null。
	 * 
	 * @param pagination
	 * @param conditions
	 * @return
	 */
	public List<T> find(Pagination pagination, List<Condition> conditions, OrderBy... orderBys) {
		return find(pagination, conditions, Arrays.asList(orderBys));
	}
	
	/**
	 * 根据分页和条件进行查询。如果不需要分页，把pagination设为null。
	 * 
	 * @param pagination
	 * @param condition
	 * @return
	 */
	public List<T> find(Pagination pagination, Condition condition, OrderBy... orderBys) {
		return find(pagination, Arrays.asList(condition), Arrays.asList(orderBys));
	}

	/**
	 * 根据分页和条件进行查询。如果不需要分页，把pagination设为null。
	 * 
	 * @param pagination
	 *            分页信息
	 * @param conditions
	 *            动态条件
	 * @param orderBy
	 *            排序方式
	 * @return
	 */
	public List<T> find(Pagination pagination, List<Condition> conditions, List<OrderBy> orderBys) {
		return baseDao.find(pagination, conditions, orderBys);
	}
	
	public List<T> find(Pagination pagination) {
		return this.find(pagination, emptyConditions);
	}

	public void save(T entity) {
		if (entity.getId() <= 0) {
			//entity.setId(BizUtils.uuid());
			baseDao.add(entity);
		} else {
			baseDao.update(entity);
		}
	}

	/**
	 * 批量保存所有实体
	 * 
	 * @param entities
	 */
	public void saveBatch(List<T> entities) {
		if (!CollectionUtils.isEmpty(entities)) {
			for (T entity : entities) {
				save(entity);
			}
		}
	}

	/**
	 * 批量插入
	 * <p>
	 * 该方式插入的实体id不会被自动填充，而且对于需要根据id进行缓存的模块，不应该使用此方法
	 * </p>
	 * 
	 * @param entities
	 *            插入的bean
	 * @param ignore
	 *            是否忽略重复key数据
	 * @return 影响条数
	 */
	public int insertBatch(List<T> entities, boolean ignore) {
		Assert.isTrue(!CollectionUtils.isEmpty(entities), "要批量插入的bean 不能卫东");
		// 生成 uuid
//		for (T b : entities) {
//			// 如果 id 不存在，则生成一个 uuid
//			if (StringUtils.isEmpty(b.getId())) {
//				b.setId(BizUtils.uuid());
//			}
//		}
		return baseDao.addBatch(entities, ignore);
	}

	/**
	 * 批量插入
	 * <p>
	 * 该方式插入的实体id不会被自动填充，而且对于需要根据id进行缓存的模块，不应该使用此方法
	 * </p>
	 * 
	 * @param entities
	 *            插入的bean
	 */
	public void insertBatch(List<T> entities) {
		Assert.isTrue(!CollectionUtils.isEmpty(entities), "要批量插入的数据不存在");
		// 生成 uuid
//		for (T b : entities) {
//			// 如果 id 不存在，则生成一个 uuid
//			if (StringUtils.isEmpty(b.getId())) {
//				b.setId(BizUtils.uuid());
//			}
//		}
		baseDao.addBatch(entities, false);
	}
	
	/**
	 * 插入一个实体
	 * @param entity
	 * @return
	 */
	public int insert(T entity){
		Assert.notNull(entity, "要插入的数据不存在");
		return baseDao.add(entity);
	}

	/**
	 * 插入单个实体
	 * @param entity
	 * @param ignore 如果插入的实体主键/唯一建存在，则忽略本次插入
	 * @return
	 */
	public int insert(T entity, boolean ignore){
		Assert.notNull(entity, "要插入的数据不存在");
		return insertBatch(Arrays.asList(entity), ignore);
	}
	
	/**
	 * 根据id的集合删除一批记录
	 * 
	 * @param ids
	 */
	public void deleteByIds(List<String> ids) {
		if (!CollectionUtils.isEmpty(ids)) {
			baseDao.deleteByIds(ids);
		}
	}

	/**
	 * 把ids对应的实体中的属性值更新成entity中所有非null的属性值
	 * 
	 * @param entity
	 * @param ids
	 */
	public void updateBatch(T entity, List<String> ids) {
		if (!CollectionUtils.isEmpty(ids)) {
			baseDao.updateBatch(entity, ids);
		}
	}

	/**
	 * 更新list中所有的实体。
	 * 
	 * @param entities
	 */
	public void updateBatch(List<T> entities) {
		if (!CollectionUtils.isEmpty(entities)) {
			for (T entity : entities) {
				save(entity);
			}
		}
	}

	/**
	 * 获取特定 id 的字段名称，用于插件处理
	 * 
	 * @param field
	 * @param id
	 * @return
	 */
	public String findFieldValueById(String field, String id) {
		if (StringUtils.isEmpty(id) || StringUtils.isEmpty(field)) {
			return null;
		}
		return baseDao.findFieldValueById(field, id);
	}

	/**
	 * 根据 编号获取已经存在的编号
	 * 
	 * @param ids
	 * @return
	 */
	public List<String> findIdsByIds(List<String> ids) {
		if (CollectionUtils.isEmpty(ids)) {
			return new ArrayList<String>(2);
		}
		return baseDao.findIdsByIds(ids);
	}

	/**
	 * 查询符合特定条件的数据数量
	 * 
	 * @param conditions
	 *            条件
	 * @return
	 */
	public int findCount(List<Condition> conditions) {
		return baseDao.findCount(conditions);
	}

}
